﻿using System;
using System.Globalization;
using Dexter.Logger.Contracts;
using log4net;
using log4net.Core;
using log4net.Util;
using ILogger = Dexter.Logger.Contracts.ILogger;

namespace Dexter.Logger.Log4Net {
	[Serializable]
	public class Log4NetLogger : MarshalByRefObject , ILogger {
		static readonly Type declaringType = typeof ( Log4NetLogger );
		static readonly IContextProperties globalContextProperties = new GlobalContextProperties ( );
		static readonly IContextProperties threadContextProperties = new ThreadContextProperties ( );
		log4net.Core.ILogger Logger { get; set; }

		/// <summary>
		/// Initializes a new instance of the <see cref="Log4NetLogger"/> class.
		/// </summary>
		public Log4NetLogger ( ) {
			this.Logger = LogManager.GetLogger ( typeof ( Log4NetLogger ) ).Logger;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Log4NetLogger"/> class.
		/// </summary>
		/// <param name="logger">The logger.</param>
		public Log4NetLogger ( ILog logger ) {
			this.Logger = logger.Logger;
		}

		#region ILogger Members

		/// <summary>
		/// Debugs the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		public void Debug ( string message ) {
			if ( this.IsDebugEnabled ) {
				this.Logger.Log ( declaringType , Level.Debug , message , null );
			}
		}

		/// <summary>
		/// Debugs the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		/// <param name="exception">The exception.</param>
		public void Debug ( string message , Exception exception ) {
			if ( this.IsDebugEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Debug , message , exception );
			}
		}

		/// <summary>
		/// Debugs the format.
		/// </summary>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void DebugFormat ( string format , params object[] args ) {
			if ( this.IsDebugEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Debug , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , null );
			}
		}

		/// <summary>
		/// Debugs the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void DebugFormat ( Exception exception , string format , params object[] args ) {
			if ( this.IsDebugEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Debug , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , exception );
			}
		}

		/// <summary>
		/// Debugs the format.
		/// </summary>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void DebugFormat ( IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsDebugEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Debug , new SystemStringFormat ( formatProvider , format , args ) , null );
			}
		}

		/// <summary>
		/// Debugs the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void DebugFormat ( Exception exception , IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsDebugEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Debug , new SystemStringFormat ( formatProvider , format , args ) , exception );
			}
		}

		/// <summary>
		/// Errors the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		public void Error ( string message ) {
			if ( this.IsErrorEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Error , message , null );
			}
		}

		/// <summary>
		/// Errors the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		/// <param name="exception">The exception.</param>
		public void Error ( string message , Exception exception ) {
			if ( this.IsErrorEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Error , message , exception );
			}
		}

		/// <summary>
		/// Errors the format.
		/// </summary>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void ErrorFormat ( string format , params object[] args ) {
			if ( this.IsErrorEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Error , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , null );
			}
		}

		/// <summary>
		/// Errors the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void ErrorFormat ( Exception exception , string format , params object[] args ) {
			if ( this.IsErrorEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Error , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , exception );
			}
		}

		/// <summary>
		/// Errors the format.
		/// </summary>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void ErrorFormat ( IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsErrorEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Error , new SystemStringFormat ( formatProvider , format , args ) , null );
			}
		}

		/// <summary>
		/// Errors the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void ErrorFormat ( Exception exception , IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsErrorEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Error , new SystemStringFormat ( formatProvider , format , args ) , exception );
			}
		}

		/// <summary>
		/// Fatals the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		public void Fatal ( string message ) {
			if ( this.IsFatalEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Fatal , message , null );
			}
		}

		/// <summary>
		/// Fatals the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		/// <param name="exception">The exception.</param>
		public void Fatal ( string message , Exception exception ) {
			if ( this.IsFatalEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Fatal , message , exception );
			}
		}

		/// <summary>
		/// Fatals the format.
		/// </summary>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void FatalFormat ( string format , params object[] args ) {
			if ( this.IsFatalEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Fatal , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , null );
			}
		}

		/// <summary>
		/// Fatals the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void FatalFormat ( Exception exception , string format , params object[] args ) {
			if ( this.IsFatalEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Fatal , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , exception );
			}
		}

		/// <summary>
		/// Fatals the format.
		/// </summary>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void FatalFormat ( IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsFatalEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Fatal , new SystemStringFormat ( formatProvider , format , args ) , null );
			}
		}

		/// <summary>
		/// Fatals the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void FatalFormat ( Exception exception , IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsFatalEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Fatal , new SystemStringFormat ( formatProvider , format , args ) , exception );
			}
		}

		/// <summary>
		/// Infoes the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		public void Info ( string message ) {
			if ( this.IsInfoEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Info , message , null );
			}
		}

		/// <summary>
		/// Infoes the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		/// <param name="exception">The exception.</param>
		public void Info ( string message , Exception exception ) {
			if ( this.IsInfoEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Info , message , exception );
			}
		}

		/// <summary>
		/// Infoes the format.
		/// </summary>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void InfoFormat ( string format , params object[] args ) {
			if ( this.IsInfoEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Info , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , null );
			}
		}

		/// <summary>
		/// Infoes the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void InfoFormat ( Exception exception , string format , params object[] args ) {
			if ( this.IsInfoEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Info , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , exception );
			}
		}

		/// <summary>
		/// Infoes the format.
		/// </summary>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void InfoFormat ( IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsInfoEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Info , new SystemStringFormat ( formatProvider , format , args ) , null );
			}
		}

		/// <summary>
		/// Infoes the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void InfoFormat ( Exception exception , IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsInfoEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Info , new SystemStringFormat ( formatProvider , format , args ) , exception );
			}
		}

		/// <summary>
		/// Warns the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		public void Warn ( string message ) {
			if ( this.IsWarnEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Warn , message , null );
			}
		}

		/// <summary>
		/// Warns the specified message.
		/// </summary>
		/// <param name="message">The message.</param>
		/// <param name="exception">The exception.</param>
		public void Warn ( string message , Exception exception ) {
			if ( this.IsWarnEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Warn , message , exception );
			}
		}

		/// <summary>
		/// Warns the format.
		/// </summary>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void WarnFormat ( string format , params object[] args ) {
			if ( this.IsWarnEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Warn , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , null );
			}
		}

		/// <summary>
		/// Warns the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void WarnFormat ( Exception exception , string format , params object[] args ) {
			if ( this.IsWarnEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Warn , new SystemStringFormat ( CultureInfo.InvariantCulture , format , args ) , exception );
			}
		}

		/// <summary>
		/// Warns the format.
		/// </summary>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void WarnFormat ( IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsWarnEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Warn , new SystemStringFormat ( formatProvider , format , args ) , null );
			}
		}

		/// <summary>
		/// Warns the format.
		/// </summary>
		/// <param name="exception">The exception.</param>
		/// <param name="formatProvider">The format provider.</param>
		/// <param name="format">The format.</param>
		/// <param name="args">The args.</param>
		public void WarnFormat ( Exception exception , IFormatProvider formatProvider , string format , params object[] args ) {
			if ( this.IsWarnEnabled ) {
				this.AddWebContextInfo ( );
				this.Logger.Log ( declaringType , Level.Warn , new SystemStringFormat ( formatProvider , format , args ) , exception );
			}
		}

		/// <summary>
		/// 	Gets the global properties.
		/// </summary>
		/// <value>The global properties.</value>
		public IContextProperties GlobalProperties {
			get { return globalContextProperties; }
		}

		/// <summary>
		/// 	Gets the thread properties.
		/// </summary>
		/// <value>The thread properties.</value>
		public IContextProperties ThreadProperties {
			get { return threadContextProperties; }
		}

		/// <summary>
		/// 	Gets the thread stacks.
		/// </summary>
		/// <value>The thread stacks.</value>
		public IContextStacks ThreadStacks {
			get { return ThreadStacks; }
		}

		/// <summary>
		/// Gets a value indicating whether this instance is debug enabled.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is debug enabled; otherwise, <c>false</c>.
		/// </value>
		public bool IsDebugEnabled {
			get { return this.Logger.IsEnabledFor ( Level.Debug ); }
		}

		/// <summary>
		/// Gets a value indicating whether this instance is error enabled.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is error enabled; otherwise, <c>false</c>.
		/// </value>
		public bool IsErrorEnabled {
			get { return this.Logger.IsEnabledFor ( Level.Error ); }
		}

		/// <summary>
		/// Gets a value indicating whether this instance is fatal enabled.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is fatal enabled; otherwise, <c>false</c>.
		/// </value>
		public bool IsFatalEnabled {
			get { return this.Logger.IsEnabledFor ( Level.Fatal ); }
		}

		/// <summary>
		/// Gets a value indicating whether this instance is info enabled.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is info enabled; otherwise, <c>false</c>.
		/// </value>
		public bool IsInfoEnabled {
			get { return this.Logger.IsEnabledFor ( Level.Info ); }
		}

		/// <summary>
		/// Gets a value indicating whether this instance is warn enabled.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is warn enabled; otherwise, <c>false</c>.
		/// </value>
		public bool IsWarnEnabled {
			get { return this.Logger.IsEnabledFor ( Level.Warn ); }
		}

		#endregion

		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString ( ) {
			return this.Logger.ToString ( );
		}
	}
}